package fda.main;

import java.util.ArrayList;
import java.util.List;

import fda.base.Constants;
import fda.base.DiskFile;
import fda.base.DiskFile2;
import fda.base.IOCounter;
import fda.base.Memory2;
import fda.base.Block;
import fda.schema.Schema;
import fda.schema.TableInfo;

import fda.hash.Hash;
import fda.hash.JoinHelper;

public class MainJoinHash {
	// main
	public static void main(String[] args) {
		// delete all files in folder when test starts
		DiskFile.clearAllFiles(Constants.PRE_BUCKET_1);
		DiskFile.clearAllFiles(Constants.PRE_BUCKET_2);
		DiskFile.clearAllFiles(Constants.PRE_SUB);
		
		////////////////////////////////////////////
		// read table description 
		////////////////////////////////////////////
		Schema schema = new Schema();
		schema.init(Constants.PRE_FILES + "schema.txt");
		
		////////////////////////////////////////////
		// build hash tables
		////////////////////////////////////////////
		
		// create two empty hash tables
		List<Hash> hashTables = new ArrayList<Hash>();
		hashTables.add(new Hash());
		hashTables.add(new Hash());
		
		// create empty bucket sublists
		List<DiskFile2> bucketList1 = new ArrayList<DiskFile2>();
		for(int i = 0; i < Constants.MAX_TYPLES_IN_BLOCK; i++) {
			bucketList1.add(new DiskFile2(new TableInfo(schema.getTables().get(0), Constants.PRE_BUCKET_1 + i), true));
		}
		List<DiskFile2> bucketList2 = new ArrayList<DiskFile2>();
		for(int i = 0; i < Constants.MAX_TYPLES_IN_BLOCK; i++) {
			bucketList2.add(new DiskFile2(new TableInfo(schema.getTables().get(1), Constants.PRE_BUCKET_2 + i), true));
		}
		
		// create a list of the 2 bucket sublist
		List<List<DiskFile2>> bucketLists = new ArrayList<List<DiskFile2>>();
		bucketLists.add(bucketList1);
		bucketLists.add(bucketList2);
		
		// for next hash table
		int next = 0;
		
		// go through both tables
		for (TableInfo table : schema.getTables()) {
			// get the table from file
			DiskFile2 source = new DiskFile2(table, true);
			
			// create as much blocks as much memory we have
			List<Block> memBlocks = Memory2.getInstance().getMemBlocks();
			
			// index in memory of blocks
			int index = 0;
			
			// go through all the blocks in file
			for(int i = 0; i < source.getBlockCount(); i++) {
				// add blocks to memory blocks
				memBlocks.add(index, source.getBlock(i));
				index++;
				// if we have reached the size of the memory
				if((i + 1) % Constants.MEMORY_SIZE_BLOCKS == 0) {
					// build the hash table from the records in memory
					hashTables.get(next).BuildHashTable(bucketLists.get(next), memBlocks);
					// clear blocks in memory
					memBlocks.clear();
					index = 0;
					// initialize memory blocks
					memBlocks = Memory2.getInstance().getMemBlocks();
				}
			}
			// if there are still some records in memory put them to the hash table
			if(memBlocks.get(0) != null) {
				hashTables.get(next).BuildHashTable(bucketLists.get(next), memBlocks);
				memBlocks.clear();
			}
			// if some records are still in bucket write them to file
			hashTables.get(next).clearTailings(bucketLists.get(next));
			
			// set it to next hash table
			next = 1;
		}
		
		// TODO: join the two hash tables
		Main.log("First file has: " + JoinHelper.getTotal(bucketList1) + " records");
		Main.log("Second file has: " + JoinHelper.getTotal(bucketList2) + " records");
		
		// Check size of buckets
		JoinHelper jh = new JoinHelper();
		jh.analyzeBuckets(hashTables.get(0).getHash(), bucketList1, bucketList2);
		
		JoinHelper.doJoin(bucketList1, bucketList2);
		Main.log("Join Done.");
		Main.log("Join Table has a structure:" + JoinHelper.JoinDiskFile.getTableInfo());
		
		// print report about all operations
		IOCounter.getInst().printReport();
	}
}
